﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Windows;
using System.Windows.Media;
using KSATouch;

// Credit: Used Josh Blake's awesome article and Blake.NUI source to understand how to promote our touch events up as WPF touch events. 
// Derived from his work on the Surface 1.0 Table device
// Also made use of Anson's blog to understand touch injection
// Josh's Blog: http://nui.joshland.org/
// Blake.NUI http://blakenui.codeplex.com/
// Anson's blog post: http://blogs.msdn.com/b/ansont/archive/2010/01/30/custom-touch-devices.aspx

namespace KSAWPFExtensions
{

    public class KSAWPFTouchDevice : TouchDevice
    {
        public Contact Contact { get; protected set; }
        private static Dictionary<int, KSAWPFTouchDevice> deviceDictionary = new Dictionary<int, KSAWPFTouchDevice>();


        public KSAWPFTouchDevice(Contact contact) : base(contact.Id)
        {
            Contact = contact;
        }

        public override System.Windows.Input.TouchPointCollection GetIntermediateTouchPoints(IInputElement relativeTo)
        {
            return new TouchPointCollection();
        }

        public override System.Windows.Input.TouchPoint GetTouchPoint(IInputElement relativeTo)
        {
            try
            {
                Point point = new Point(this.Contact.CenterPoint.X, this.Contact.CenterPoint.Y);
                if (relativeTo != null)
                {
                    point = this.ActiveSource.RootVisual.TransformToDescendant((Visual)relativeTo).Transform(point);
                }

                Rect rect = this.Contact.ContactBlob.BoundingBox;
                TouchPoint touchPoint = new TouchPoint(this, point, rect, TouchAction.Move);
                //touchPoint.Contact = this.Contact;
                return touchPoint;
            }
            catch (InvalidOperationException)
            {
                // Note: This fixes a crash where a finger on an element which is removed
                // from the tree causes an IVO exception
                Rect rect = this.Contact.ContactBlob.BoundingBox;
                TouchPoint touchPoint = new TouchPoint(this, new Point(this.Contact.CenterPoint.X, this.Contact.CenterPoint.Y), rect, TouchAction.Move);
                return touchPoint;
            }
            catch (Exception)
            {
                return null;
            }
        }

        public static Contact GetContact(TouchDevice device)
        {
            try
            {
                KSAWPFTouchDevice ksaDevice = device as KSAWPFTouchDevice;

                if (ksaDevice == null)
                    return null;

                return ksaDevice.Contact;
            }
            //Ignore InvalidOperationException at this time
            catch (InvalidOperationException)
            {
                System.Diagnostics.Debug.WriteLine("GetContact threw an IVO!");
            }
            return null;
        }


        public static void KSAContact_Changed(object sender, ContactEventArgs e)
        {
            
            try
            {
                int id = e.Contact.Id;
                if (!deviceDictionary.Keys.Contains(id))
                {
                    KSAContact_Down(sender, e);
                }

                KSAWPFTouchDevice device = deviceDictionary[id];
                if (device != null &&
                    device.IsActive)
                {
                    device.Contact = e.Contact;
                    device.ReportMove();
                }
            }
            //Ignore InvalidOperationException at this time
            catch (Exception)
            {
                System.Diagnostics.Debug.WriteLine("ReportMove was not called!");
            }
        }
        public static void KSAContact_Down(object sender, ContactEventArgs e)
        {
            try
            {
                KSAWPFTouchDevice device = new KSAWPFTouchDevice(e.Contact);
                deviceDictionary.Add(e.Contact.Id, device);

                device.SetActiveSource(PresentationSource.FromVisual((Window)sender));
                device.Activate();
                device.ReportDown();
            }
            catch (InvalidOperationException)
            {
                System.Diagnostics.Debug.WriteLine("Contact Down threw an IVO!");
            }
        }
        public static void KSAContact_Up(object sender, ContactEventArgs e)
        {
            try
            {
                int id = e.Contact.Id;
                KSAWPFTouchDevice device = deviceDictionary[id];

                if (device != null &&
                    device.IsActive)
                {
                    try
                    {
                        device.ReportUp();
                    }
                    catch (Exception)
                    {

                    }
                    device.Deactivate();
                    deviceDictionary.Remove(id);
                }
            }
            catch (InvalidOperationException)
            { }
        }
        public static void KSAContact_Down2(object sender, ContactEventArgs e)
        {
            try
            {
                if (deviceDictionary.Keys.Contains(e.Contact.Id))
                {
                    KSAContact_Up(sender, e);
                    return;
                }
                KSAWPFTouchDevice device = new KSAWPFTouchDevice(e.Contact);
                deviceDictionary.Add(e.Contact.Id, device);

                device.SetActiveSource(PresentationSource.FromVisual((Window)sender));
                device.Activate();
                device.ReportDown();
            }
            catch (InvalidOperationException)
            {
                System.Diagnostics.Debug.WriteLine("Contact Down threw an IVO!");
            }
        }

        public static void KSAContact_Up2(object sender, ContactEventArgs e)
        {
            try
            {
                int id = e.Contact.Id;
                if (!deviceDictionary.Keys.Contains(id))
                {
                    KSAContact_Down(sender, e);
                }
                KSAWPFTouchDevice device = deviceDictionary[id];

                if (device != null &&
                    device.IsActive)
                {
                    try
                    {
                        device.ReportUp();
                    }
                    catch (Exception)
                    {

                    }
                    device.Deactivate();
                    deviceDictionary.Remove(id);
                }
            }
            catch (InvalidOperationException)
            { }

        }

    }
}
